// *** LICENSE HEADER ***
// Filename: ./particlesystem.cpp
// This file is part of Nodewarz 0.1
// Nodewarz is a 3d OpenGL strategy game
// Copyright (C) 2007 CZestmyr
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License along
// with this program; if not, write to the Free Software Foundation, Inc.,
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
// *** END LICENSE HEADER ***
#include "particlesystem.h"

particleSystem::particleSystem() {
    //Create emitter buffer
    emitters = new particleEmitter*[16];

    //Imit emitter freed handle buffer
    freedHandles = new int[16];
    freedHandleNumber = 0;

    //Init emitter buffer
    emitterNumber = 0;
    emitterBufferSize = 16;
    for (int i = 0; i < 16; ++i) {
        textures[i] = 0;
    }
}

particleSystem::~particleSystem() {
    for (int i = 0; i < emitterNumber; ++i)
        if (emitters[i] != 0)
            delete emitters[i];
    delete[] emitters;
    delete[] freedHandles;
    for (int i = 0; i < 16; ++i) {
        UnloadParticleTexture(i);
    }
}

int particleSystem::CreateEmitter(float x, float y, float z, int textureHandle,
                                  int t, float otherX, float otherY, float otherZ) {
    //If there are some free emitter slots, use the first one
    if (freedHandleNumber != 0) {
        --freedHandleNumber;
        emitters[freedHandles[freedHandleNumber]] = new particleEmitter(x, y, z, textures[textureHandle], t, otherX, otherY, otherZ);
        emitters[freedHandles[freedHandleNumber]]->SetParentData(this, freedHandles[freedHandleNumber]);
        return freedHandles[freedHandleNumber];
    }

    //If the emitter buffer is full, enlarge it
    if (emitterNumber == emitterBufferSize)
        ReallocateBuffer();

    //Add the new emitter to the end of the buffer
    emitters[emitterNumber] = new particleEmitter(x, y, z, textures[textureHandle], t, otherX, otherY, otherZ);
    emitters[emitterNumber]->SetParentData(this, emitterNumber);
    ++emitterNumber;
    return emitterNumber - 1;
}

void particleSystem::RemoveEmitter(int handle) {
    //Check correctness of the handle
    if (handle < 0) return;
    //Check if the emitter still exists
    if (handle >= emitterNumber) return;
    if (emitters[handle] == 0) return;
    delete emitters[handle];
    emitters[handle] = 0;

    //Set this emitter's handle as freed
    freedHandles[freedHandleNumber] = handle;
    ++freedHandleNumber;
}

void particleSystem::LoadParticleTexture(int textureHandle, const char* filename) {
    UnloadParticleTexture(textureHandle);
    textures[textureHandle] = LoadTexture(filename);
}

void particleSystem::UnloadParticleTexture(int textureHandle) {
    if (textures[textureHandle] == 0) return;
    UnloadTexture(textures[textureHandle]);
}

void particleSystem::Update(int dt) {
    //Update all used emitter slots
    for (int i = 0; i < emitterNumber; ++i) {
        if (emitters[i] == 0) continue;
        emitters[i]->Update(dt);
    }
}

void particleSystem::Draw() {
    //Draw all emitters
    for (int i = 0; i < emitterNumber; ++i) {
        if (emitters[i] == 0) continue;
        emitters[i]->Draw();
    }
}

void particleSystem::ReallocateBuffer() {
    particleEmitter** newE = new particleEmitter*[emitterBufferSize * 2];
    memcpy(newE, emitters, emitterBufferSize * sizeof(particleEmitter*));
    delete[] emitters;
    emitters = newE;
    int* newF = new int[emitterBufferSize * 2];
    memcpy(newF, freedHandles, emitterBufferSize * sizeof(int));
    delete[] freedHandles;
    freedHandles = newF;
    emitterBufferSize *= 2;
}
